package com.cs.vessel.breakdown;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.UUID;

import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.internal.server.RepositoryConfigurator;
import org.eclipse.emf.cdo.net4j.CDONet4jUtil;
import org.eclipse.emf.cdo.net4j.CDOSession;
import org.eclipse.emf.cdo.net4j.CDOSessionConfiguration;
import org.eclipse.emf.cdo.server.CDOServerUtil;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.net4j.connector.IConnector;
import org.eclipse.net4j.jvm.IJVMAcceptor;
import org.eclipse.net4j.jvm.JVMUtil;
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.xml.sax.SAXException;

import com.sc.vessel.info.model.breakdown.BreakdownFactory;
import com.sc.vessel.info.model.breakdown.BreakdownPackage;
import com.sc.vessel.info.model.breakdown.Component;
import com.sc.vessel.info.model.breakdown.ConfigElement;
import com.sc.vessel.info.model.breakdown.Configuration;

/**
 * The activator class controls the plug-in life cycle
 */
@SuppressWarnings("restriction")
public class Activator extends AbstractUIPlugin {

    // The plug-in ID
    public static final String PLUGIN_ID = "com.cs.vessel.breakdown"; //$NON-NLS-1$

    // The shared instance
    private static Activator plugin;

    /**
     * The repository name
     */
    private static final String REPOSITORY_NAME = "vessel_repository"; //$NON-NLS-1$

    /**
     * The constructor
     */
    public Activator() {
    }

    private IJVMAcceptor acceptor = null;

    private IConnector connector = null;

    private IRepository repository = null;

    private CDOSession session = null;

    private CDOTransaction transaction = null;

    private Process serverProcess;

    /**
     * 
     */
    public static final String RES_NAME = "/breakdownRes"; //$NON-NLS-1$

    public static final String RES_CONFIG_NAME = "/configurationRes"; //$NON-NLS-1$

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
     */
    public void start(BundleContext context) throws Exception {
        super.start(context);

        startHSQLDB();
        Thread.sleep(5000);
        plugin = this;
        // init the CDOSession
        getSession();
        initCDOResrouce();
    }

    /**
     * DOC liaoqc Comment method "startHSQLDB".
     * 
     * @throws IOException
     */
    private void startHSQLDB() throws IOException {
        //
        IPath path = Platform.getLocation();
        String dir = path.toFile().getParent().toString();
        serverProcess = Runtime.getRuntime().exec(
                "cmd /c start /b " + dir + File.separator + "hsqldb" + File.separator + "bin" + File.separator
                        + "runCDOHibernate.bat");
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) throws Exception {
        stopHSQLDB();
        plugin = null;
        if (transaction != null)
            LifecycleUtil.deactivate(transaction);

        if (session != null)
            LifecycleUtil.deactivate(session);

        if (acceptor != null)
            LifecycleUtil.deactivate(acceptor);

        if (connector != null)
            LifecycleUtil.deactivate(connector);

        if (repository != null)
            LifecycleUtil.deactivate(repository);

        super.stop(context);
    }

    /**
     * DOC liaoqc Comment method "stopHSQLDB".
     * 
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    private void stopHSQLDB() throws SQLException, ClassNotFoundException {
        Class.forName("org.hsqldb.jdbcDriver");
        Connection conn = DriverManager.getConnection("jdbc:hsqldb:hsql://localhost/cdohibernate", "sa", "");
        Statement statement = conn.createStatement();
        statement.executeUpdate("SHUTDOWN;");
        statement.close();
        conn.close();
    }

    /**
     * Getter for session including lazy initialization
     * 
     * @return the CDO session
     */
    public CDOSession getSession() {
        if (session == null) {
            IManagedContainer container = IPluginContainer.INSTANCE;

            // initialize acceptor
            if (acceptor == null)
                acceptor = JVMUtil.getAcceptor(container, "default"); //$NON-NLS-1$

            if (repository == null) {
                try {
                    repository = createRepository();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                CDOServerUtil.addRepository(container, repository);
            }

            if (connector == null)
                connector = JVMUtil.getConnector(container, "default"); //$NON-NLS-1$

            CDOSessionConfiguration config = CDONet4jUtil.createSessionConfiguration();
            config.setConnector(connector);
            config.setRepositoryName(REPOSITORY_NAME);
            session = config.openSession();
        }
        return session;
    }

    /**
     * Getter for transaction including lazy initialization
     * 
     * @return the transaction
     */
    public CDOTransaction getTransaction() {
        if (transaction == null) {
            transaction = getSession().openTransaction();
        }

        return transaction;
    }

    /**
     * Create and initialize/configure a repository
     * 
     * @return the CDO repository created
     * @throws IOException
     */
    private IRepository createRepository() throws IOException {
        Bundle hibernateServerBundle = Platform.getBundle("org.eclipse.emf.cdo.examples.hibernate.server"); //$NON-NLS-1$
        URL url = hibernateServerBundle.getResource("/config/cdo-server.xml"); //$NON-NLS-1$
        File configFile = new File(FileLocator.toFileURL(url).getFile()); //$NON-NLS-1$
        IRepository[] repositories = null;
        if (configFile != null && configFile.exists()) {
            RepositoryConfigurator repositoryConfigurator = new RepositoryConfigurator(IPluginContainer.INSTANCE);
            try {
                repositories = repositoryConfigurator.configure(configFile);
            } catch (ParserConfigurationException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (CoreException e) {
                e.printStackTrace();
            }
        }
        if (repositories != null) {
            return repositories[0];
        }
        return null;
    }

    /**
     * DOC liaoqc Comment method "initCDOResrouce".
     */
    private void initCDOResrouce() {
        session.getPackageRegistry().putEPackage(BreakdownPackage.eINSTANCE);
        final CDOTransaction transaction = session.openTransaction();
        // get/create a resource
        CDOResource accidentResource = transaction.getOrCreateResource(RES_NAME);
        // create the init data
        if (accidentResource.getContents().size() == 0) {
            Component component = BreakdownFactory.eINSTANCE.createComponent();
            component.setName(Messages.ACTIVATOR_VESSEL_ACCIDENT);
            component.setItemId(UUID.randomUUID().toString());
            accidentResource.getContents().add(component);
        }
        // get/create configuration resource
        CDOResource configResource = transaction.getOrCreateResource(RES_CONFIG_NAME);
        // create the init data
        if (configResource.getContents().size() == 0) {
            Configuration configuration = BreakdownFactory.eINSTANCE.createConfiguration();
            initConfiguration(configuration);
            configResource.getContents().add(configuration);
        }
        try {
            transaction.commit();
        } catch (CommitException e) {
            e.printStackTrace();
        }
    }

    /**
     * DOC liaoqc Comment method "initConfiguration".
     * 
     * @param configuration
     */
    private void initConfiguration(Configuration configuration) {
        String[] configElementNames = new String[] { Messages.ACTIVATOR_ACCIDENT_KIND, Messages.ACTIVATOR_REASON,
                Messages.ACTIVATOR_MACHINE_TYPE, Messages.ACTIVATOR_OCCURRENCE_TIME, Messages.ACTIVATOR_OCCURRENCE_AREA,
                Messages.ACTIVATOR_PERSON_IN_CHARGE, Messages.ACTIVATOR_AFTERMATH };
        for (int i = 0; i < configElementNames.length; i++) {
            ConfigElement configElement = BreakdownFactory.eINSTANCE.createConfigElement();
            configElement.setName(configElementNames[i]);
            configElement.setItemId(UUID.randomUUID().toString());
            configElement.setOrder(i);
            configuration.getElements().add(configElement);
        }
    }

    /**
     * Returns the shared instance
     * 
     * @return the shared instance
     */
    public static Activator getDefault() {
        return plugin;
    }

    /**
     * Returns an image descriptor for the image file at the given plug-in relative path
     * 
     * @param path the path
     * @return the image descriptor
     */
    public static ImageDescriptor getImageDescriptor(String path) {
        return imageDescriptorFromPlugin(PLUGIN_ID, path);
    }
}
